package cn.edu.glut.utils;

import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.assertj.core.util.Sets;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.BeansException;

import com.sargeraswang.util.ExcelUtil.ExcelLogs;
import com.sargeraswang.util.ExcelUtil.ExcelUtil;

import cn.edu.glut.entity.Major;
import cn.edu.glut.entity.Student;
import cn.edu.glut.exception.ExcelException;
import cn.edu.glut.vo.StudentExcelVo;


/**
 * 
 * @author Caizhfy
 * @version v.0.1
 * @createTime 2017年12月12日下午3:40:55
 * @email Caizhfy@163.com
 * @description excel导入导出工具
 *
 */
public class ExcelUtils {
	
	private static final Logger logger = LoggerFactory.getLogger(ExcelUtils.class);
	
	/**
	 * 泛型：V代表Vo，B代表该Vo相对应的Bean实体
	 * @param voClazz 传入的VoBean的类型，也就是泛型类的类型，内部会自动将每行转换成为Vo对象
	 * @param beanClazz 传入的是需要转入的实体类型
	 * @param in	excel文件流
	 * @param dateFormatPattern 如果有date类型，那么需要的格式是什么（符合SimpleDateFormat规范）
	 * @param arrayIndex 默认情况应当为0，该参数表明如果bena中有数组，那么需要按逻辑
	 * @param logs 如果导入出错，那么会报错信息
	 * @param  majorMap 专业名称与其id的键值对
	 * @throws IllegalAccessException 
	 * @throws InstantiationException 
	 * @throws BeansException 
	 * @throws SecurityException 
	 * @throws NoSuchFieldException 
	 */
	public static <V, B> Collection<B> importExcel(Class<V> voClazz, Class<B> beanClazz, InputStream in,
			String dateFormatPattern, int arrayIndex, ExcelLogs logs, Map<String, String> majorMap) throws Exception {
		logger.info("开始导入数据...");
		// excel导出得出vo实体集合
		Collection<V> voList = ExcelUtil.importExcel(voClazz, in, dateFormatPattern, logs, arrayIndex);
		Iterator<V> voIterator = null;
		if (null != voList && voList.size() != 0)
			voIterator = voList.iterator();
		Set<B> beanList = copyVoToEntityBean(voClazz, beanClazz, voIterator, majorMap);
		return beanList;
	}
	
	
	// 将Vo转换成实体Bean以便于SpringData持久化,实体bean
	private static<V,B> Set<B> copyVoToEntityBean(Class<V> voClazz, Class<B> beanClazz, Iterator<V> voIterator, Map<String, String> majorMap) throws Exception{
		Set<B> beanList = Sets.newHashSet();
		int lineCount = 0;		//尝试转换条数
		while (null!=voIterator && voIterator.hasNext()) {
			lineCount ++;
			V vo = voIterator.next();
			// 判断一下vo中的数据属性是否已经满足了后面需要插入的条件，如果属性不够，这条数据就算是不过关的，不给予转换
			Method isFullData = voClazz.getDeclaredMethod("isFullData", null);
			if (!(boolean) isFullData.invoke(vo, null)) {
				throw new ExcelException("第 " + lineCount + " 行数据不能导入，因为数据不全，请补全数据在导入");
			}
			B bean = beanClazz.newInstance();
			BeanUtils.copyProperties(vo, bean);
			//如果导入的是学生实体，在这里需要处理关联该学生所属专业
			if(beanClazz==Student.class && voClazz==StudentExcelVo.class && null!=majorMap){
				Student s = (Student)bean;
				StudentExcelVo svo = (StudentExcelVo) vo;
				importMajorToStudent(majorMap, s, svo);
			}
			beanList.add(bean);
			logger.info(bean.toString());
		}
		return beanList;
	}
	
	public static<V> void exportExcel(Map<String, String> columKeyMap, Collection<V> exportEntities, OutputStream out){
		ExcelUtil.exportExcel(columKeyMap, exportEntities, out);
	}
	
	public static boolean isExcelFile(String fileName){
		String regex = "^.+\\.xl\\w{1,2}$";
		if(!StringUtils.isEmpty(fileName) && fileName.matches(regex))
			return true;
		return false;
	}
	
	//如果是学生，需要直接性的处理导入其专业
	private static void importMajorToStudent(Map<String, String> majorMap, Student s, StudentExcelVo vo){
		String majorStr = vo.getMajorName();
		String majorId = null;
		if(!StringUtils.isEmpty(majorStr))
			majorId = majorMap.get(majorStr);
		if(StringUtils.isEmpty(majorId))
			throw new ExcelException("学号: " + vo.getUsername()+"姓名: " + vo.getNickname() + " ,该学生所属的专业:" + vo.getMajorName() + "不存在，请检查再进行导入操作");
		Major m = new Major(majorId);
		s.setMajor(m);
	}
	
}
